﻿using RestSharp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        private static string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYjVhNGMwNDEtMmJkMC00ODYyLTkwOGYtOTRjNTgwZGIzZDRjIiwiZXhwIjoxNTY0NDQ4NDAwLCJpc3MiOiJHcm93aW5nIiwiYXVkIjoiOTRkNjA3ZTItZDU2NS00MzBmLWE4YmItMzVhMGRhNzBiZWI2In0.7BcjYKRhchbnlPSjM923I2t-MDBwWFefX6TxITtKoc8";

        private static string ServerURL = "http://192.168.101.100:8081/big/upload/";

        private static string URL = "http://192.168.101.100:8081/upload";

        static void Main(string[] args)
        {
            var testfile = GenFileText(5);
            string md5 = GenMd5Str(testfile);
            // string md5 = "0fe0d7386a78d1a50e924686e14adfe6";

            UploadWithProgress(testfile);

            string result = GetServerFileInfo(md5);
            Console.WriteLine(result);

            var fileUrl = Newtonsoft.Json.Linq.JObject.Parse(result)["url"].ToString();
            VerifyUpload(fileUrl, testfile);

            // Cleanup
            File.Delete(testfile.FullName);

            Console.WriteLine("Press the any key");
            Console.ReadKey();
        }

        static FileInfo GenFileText(long sizeInMb)
        {
            Console.WriteLine("请输入要生成文件的内容：");
            string input = Console.ReadLine();

            Console.WriteLine("正在生成Text测试文件...");
            var fi = new FileInfo("random.txt");
            if (fi.Exists)
            {
                fi.Delete();
            }

            long sizeInBytes = sizeInMb * 1024 * 1024;
            long bytesWritten = 0;

            using (var fs = new FileStream(fi.FullName, FileMode.Create))
            {
                using (var sw = new BinaryWriter(fs))
                {
                    while (bytesWritten < sizeInBytes)
                    {
                        var charsbytes = Encoding.UTF8.GetBytes(input);
                        sw.Write(charsbytes);
                        bytesWritten += charsbytes.Length;
                    }
                }
            }

            fi = new FileInfo(fi.FullName);
            return fi;
        }

        static void UploadWithProgress(FileInfo testfile)
        {
            var sw = new Stopwatch();
            double bytesTransferredLast = 0;
            double transferRate = 0;

            double previousPercentage = 0;

            var tc = new TusClient.TusClient();
            tc.Uploading += (long bytesTransferred, long bytesTotal) =>
              {
                  if (sw.Elapsed.TotalSeconds > 0)
                  {
                      transferRate = (bytesTransferred - bytesTransferredLast) / sw.Elapsed.TotalSeconds;
                  }

                  double perc = Convert.ToDouble(bytesTransferred) / Convert.ToDouble(bytesTotal) * 100.0;
                  perc = Math.Truncate(perc);
                  if (perc != previousPercentage)
                  {
                      Console.WriteLine("已上传: {0:0.00}% {1} of {2} 瞬时上传速度：{3}/second", perc, HumanizeBytes(bytesTransferred), HumanizeBytes(bytesTotal), HumanizeBytes(transferRate));
                      previousPercentage = perc;
                  }

                  // calc transfer rate over the last second
                  if (sw.Elapsed.TotalSeconds > 1)
                  {
                      bytesTransferredLast = bytesTransferred;
                      sw.Restart();
                  }
              };

            //Dictionary<string, string> dic = new Dictionary<string, string>();
            //dic.Add("auth_token", token);
            var fileUrl = tc.Create(ServerURL, testfile);
            sw.Start();
            tc.Upload(fileUrl, testfile);
            sw.Stop();

            //var serverInfo = tc.getServerInfo(ServerURL);
            //if (serverInfo.SupportsDelete)
            //{
            //    if (tc.Delete(fileUrl))
            //    {
            //        Console.WriteLine("Upload Terminated");
            //    }
            //    else
            //    {
            //        Console.WriteLine("Upload Terminated FAILED");
            //    }
            //}
        }

        static string GenMd5Str(FileInfo fi)
        {
            var md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            var localBytes = File.ReadAllBytes(fi.FullName);
            byte[] retVal = md5.ComputeHash(localBytes);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < retVal.Length; i++)
            {
                sb.Append(retVal[i].ToString("x2"));
            }

            return sb.ToString();
        }

        static string GetServerFileInfo(string md5hashLocal)
        {
            var client = new RestClient(URL);
            var request = new RestRequest(Method.GET);
            request.AddQueryParameter("md5", md5hashLocal);
            request.AddQueryParameter("output", "json");
            request.AddQueryParameter("auth_token", token);
            IRestResponse response = client.Execute(request);
            return response.Content;
        }

        static string HumanizeBytes(double bytes)
        {
            double res = bytes;
            if (res < 1024)
            {
                return string.Format("{0:n2} b", res);
            }

            res = res / 1024;
            if (res < 1024)
            {
                return string.Format("{0:n2} Kb", res);
            }

            res = res / 1024;
            if (res < 1024)
            {
                return string.Format("{0:n2} Mb", res);
            }

            res = res / 1024;
            return string.Format("{0:n2} Gb", res);
        }

        static void VerifyUpload(string fileUrl, FileInfo fi)
        {
            Console.WriteLine("正在检测上传文件...");

            var sha = new System.Security.Cryptography.SHA1CryptoServiceProvider();

            var localBytes = File.ReadAllBytes(fi.FullName);
            var sha1hashLocal = BitConverter.ToString(sha.ComputeHash(localBytes));

            var tc = new TusClient.TusClient();
            var response = tc.Download(fileUrl);

            if (localBytes.Length != response.ResponseBytes.Length)
            {
                throw new Exception("文件大小不匹配!");
            }

            var sha1hashRemote = BitConverter.ToString(sha.ComputeHash(response.ResponseBytes));

            if (sha1hashLocal != sha1hashRemote)
            {
                throw new Exception("文件哈希值不匹配!");
            }
            else
            {
                Console.WriteLine("上传文件和下载文件哈希值对比: {0}", sha1hashRemote.Replace("-", ""));
            }
        }
    }
}
